import os
import struct

def calc_crc32(data):
    """计算CRC32，与MCU端使用相同算法"""
    crc = 0xFFFFFFFF
    
    for byte in data:
        crc ^= byte
        for _ in range(8):
            if crc & 1:
                crc = (crc >> 1) ^ 0xEDB88320
            else:
                crc >>= 1
    
    return ~crc & 0xFFFFFFFF

class FirmwareUpdater:
    def __init__(self, client):
        self.client = client
        self.BLOCK_SIZE = 1024    # 1KB
        self.TOTAL_BLOCKS = 60    # 60KB
        
    def update_firmware(self, firmware_path, progress_callback=None):
        """更新固件
        
        Args:
            firmware_path: 固件文件路径
            progress_callback: 进度回调函数，参数为0-100的进度值
            
        Returns:
            True表示成功，失败则抛出异常
        """
        # 检查文件是否存在
        if not os.path.exists(firmware_path):
            raise Exception("固件文件不存在")
            
        # 读取固件文件
        with open(firmware_path, 'rb') as f:
            firmware_data = f.read()
            
        # 检查文件大小
        if len(firmware_data) > self.TOTAL_BLOCKS * self.BLOCK_SIZE:
            raise Exception("固件文件过大")
            
        # 初始化CRC
        crc = 0xFFFFFFFF
        
        # 按块发送
        for block in range(self.TOTAL_BLOCKS):
            # 准备这个块的数据
            start = block * self.BLOCK_SIZE
            end = start + self.BLOCK_SIZE
            
            if start >= len(firmware_data):
                # 如果已经发送完所有数据，用0xFF填充剩余块
                block_data = b'\xFF' * self.BLOCK_SIZE
            else:
                # 取出这个块的数据，不足1KB的用0xFF填充
                block_data = firmware_data[start:end].ljust(self.BLOCK_SIZE, b'\xFF')
            
            # 更新CRC
            block_crc = calc_crc32(block_data)
            crc = block_crc
            
            # 发送数据块
            if not self.client.write_firmware_block(block, block_data):
                raise Exception(f"写入块{block}失败")
                
            # 更新进度
            if progress_callback:
                progress = (block + 1) / self.TOTAL_BLOCKS * 100
                progress_callback(progress)
        
        # 验证固件
        if not self.client.verify_firmware(crc):
            raise Exception("固件验证失败")
        
        # 激活固件
        if not self.client.activate_firmware():
            raise Exception("固件激活失败")
            
        return True
